<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>

	<body>
		<script type="text/javascript">
			(function(window, undefined) {
				
				_jQuery = window.jQuery;
				_$ = window.$;
				
				var jQuery = (function() {
					class2type = {
						"[object Array]": "array",
						"[object Boolean]": "boolean",
						"[object Date]": "date",
						"[object Function]": "function",
						"[object Number]": "number",
						"[object Object]": "object",
						"[object RegExp]": "regexp",
						"[object String]": "string"
					};


					/**
					 * 引用对象
					 */
					core_push = Array.prototype.push;
					//复制数组[begin,end)
					core_slice = Array.prototype.slice;
					core_indexOf = Array.prototype.indexOf;
					core_toString = Object.prototype.toString;
					core_hasOwn = Object.prototype.hasOwnProperty;
					core_trim = String.prototype.trim;

					var jQuery = function(selector, context, rootjQuery) {
						return new jQuery.fn.init(selector, context, rootjQuery);
					};

					jQuery.fn = jQuery.prototype = {
						constructor: jQuery,
						init: function(selector, context, rootjQuery) {
							console.log('init');
						},
						selector: "",
						jquery: "1.7.1-test",
						length: 0,
						size: function() {
							return this.length;
						},
						toArray: function() {
							return core_slice.call(this, 0);
						},
						get: function(num) {
							return num == null ? this.toArray() : (num < 0 ? this[this.length + num] : this[num]);
						},
						/**
						 * 创建一个新的空的jquery对象，并把DOM元素集合放到这个对象中
						 * @param {Object} elems
						 * @param {Object} name 产生元素数组elems的jquery方法名
						 * @param {Object} selector
						 */
						pushStack: function(elems,name,selector) {
							//创建一个新的空的jquery对象
							var ret = this.constructor();
							if(jQuery.isArray(elems)){
								core_push.apply(ret,elems);
							}else{
								jQuery.merge(ret,elems);
							}
							
							ret.prevObject = this;
							
							ret.context = this.context;
							
							if(name==='find'){
								ret.selector = this.selector +(this.selector?' ':'')+selector;
							}else if(name){
								ret.selector = this.selector +'.'+name+'('+selector+')';
							}
							return ret;
						},
						each: function(callback, args) {
							return jQuery.each(this, callback, args);
						},
						ready: function() {

						},
						eq: function(i) {
    						//如果是+ "xx"那么就会返回0，typeof还是会返回number 通过typeof +"123"将返回number   
							i=+i;
							return i===-1?this.slice(i):this.slice(i,i+1);
						},
						first: function() {
							return this.eq(0);
						},
						last: function() {
							return  this.eq(-1);
						},
						slice: function() {
							return this.pushStack(core_slice.apply(this,arguments),'slice',core_slice.call(arguments).join(','));
						},
						/**
						 * 执行回调函数返回的结果放入新的jQuery中
						 * @param {Object} callback
						 */
						map: function(callback) {
							return this.pushStack(jQuery.map(this,function(elem,i){
								return callback.call(elem,i,elem);
							}));
						},
						/**
						 * 结束当前筛选操作，并将匹配元素集合还原为之前状态
						 */
						end: function() {
							return this.prevObject || this.constructor(null);
						},
						push: core_push,
						sort: [].sort,
						splice: [].splice
					};
					jQuery.fn.init.prototype = jQuery.fn;

					/**
					 * deep 是否深度复制
					 * target 目标对象
					 * source.. 源对象多个
					 */
					jQuery.extend = jQuery.fn.extend = function() {
						var target = arguments[0] || {}, //目标对象
							i = 1,
							/*源对象下标*/
							deep = false,
							length = arguments.length,
							options, name, src, copy, copyIsArray, clone;
						if(typeof target === 'boolean') {
							//第一个参数为deep情况
							deep = target;
							target = arguments[i] || {};
							i++;
						}
						if(typeof target != 'object' && !jQuery.isFunction(target)) {
							//处理targe为 string等其他类型
							target = {};
						}
						if(length === i) {
							//只有一个参数，并且不是boolean的，目标对象为jquery
							target = this;
							i--;
						}
						for(; i < length; i++) {
							if((options = arguments[i]) != null) {
								for(name in options) {
									src = target[name];
									copy = options[name];
									if(target === options) {
										continue;
									}
									if(deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
										if(copyIsArray) {
											//复制的是数组
											copyIsArray = false;
											clone = src && jQuery.isArray(src) ? src : [];
										} else {
											clone = src && jQuery.isPlainObject(src) ? src : {};
										}
										target[name] = jQuery.extend(deep, clone, copy)
									} else if(copy != undefined) {
										target[name] = copy;
									}
								}
							}
						}
						return target;
					}

					//jQuery静态方法
					jQuery.extend({
						/**
						 * 释放全局变量$,
						 * 
						 * @param {Object} deep
						 */
						noConflict:function(deep){
							if(window.$ === jQuery){
								window.$=_$;
							}
							if(deep && window.jQuery === jQuery){
								window.jQuery = _jQuery;
							}
							
							return jQuery;
						},
						isReady:false,
						readyWait:1,
						holdReady:function(hold){
							
						},
						/**
						 * 原始类型
						 * @param {Object} obj
						 */
						type: function(obj) {
							return obj == null ? new String(obj) : class2type[toString.call(obj)] || "object";
						},
						/**
						 * 判断fn是不是函数
						 * @param {Object} fn
						 */
						isFunction: function(fn) {
							//修复ie中alert、window.open、document.getElementId typeof为object
							if("object" === typeof document.getElementById) {
								try {
									return /^\s*\bfunction\b/.test(obj + '');
								} catch(e) {
									return false;
								}
							}
							return "[object Function]" === Object.prototype.toString.call(fn);
						},
						/**
						 * obj是不是一个通过{}或new Object 创建的
						 * @param {Object} obj
						 */
						isPlainObject: function(obj) {
							if(jQuery.type(obj) !== 'object' || obj.nodeType || jQuery.isWindow(obj)) {
								return false;
							}
							try {
								if(obj.constructor && !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
									return false;
								}
							} catch(e) {
								return false;
							}
							return true;
						},
						/**
						 * 判断是不是数组类型
						 * @param {Object} obj
						 */
						isArray: Array.isArray || function(obj) {
							console.log('isArray')
							return jQuery.type(obj) === "array";
						},
						/**
						 * 判断是不是数组，包含类数组对象
						 * eg:var eg ={'0':2,'1':5,'2':3,'length':3}
						 * @param {Object} obj
						 */
						isArrayLike: function(obj) {
							var length = obj.length,
								type = jQuery.type(obj);
							if(type == 'function' || jQuery.isWindow(obj)) {
								//window和function都有length
								return false;
							}
							if(obj.nodeType == 1 && length) {
								//Element节点
								return true;
							}
							//typeof length==='number'&&length>0&&(length-1) in obj 针对类数组对象
							//eg:var eg ={'0':2,'1':5,'2':3,'length':3}
							return type === 'array' || length === 0 || typeof length === 'number' && length > 0 && (length - 1) in obj;
						},
						/**
						 * 判断是不是window对象
						 * @param {Object} obj
						 */
						isWindow: function(obj) {
							return obj != null && obj == obj.window; //windows对象有个属性指向自身
						},

						each: function(object, callback, args) {
							var name, i = 0,
								length = object.length,
								isObj = length === undefined || jQuery.isFunction(object);
							if(args) {
								if(isObj) {
									for(name in object) {
										if(callback.apply(object[name], args) === false) {
											break;
										}
									}
								} else {
									for(; i < length;) {
										if(callback.apply(object[i++], args) === false) {
											break;
										}
									}
								}
							} else {
								if(isObj) {
									for(name in object) {
										if(callback.call(object[name], name, object[name]) === false) {
											break;
										}
									}
								} else {
									for(; i < length;) {
										console.log(object[i])
										if(callback.call(object[i], i, object[i++]) === false) {
											break;
										}
									}
								}
							}
						},
						/**
						 * 对elems中的每个元素执行callback方法，并将每个结果放入数组中返回
						 * @param {Object} elems
						 * @param {Object} callback
						 * @param {Object} arg
						 */
						map: function(elems, callback, arg) {
							var value, key, ret = [],
								i = 0,
								length = elems.length,
								isArray = elems instanceof jQuery　 || 　length !== undefined && typeof length === 'number' && ((length > 0 && elems[0] && elems[length - 1]) || length === 0 || jQuery.isArray(elems));

							if(isArray) {
								// 变量数组，如果返回值不为null，将回调函数的返回值加入到返回数组中
								for(; i < length; i++) {
									value = callback(elems[i], i, arg)
									if(value != null) {
										ret[ret.length] = value;
									}
								}
							} else {
								for(name in elems) {
									value = callback(elems[name], name, arg);
									if(value != null) {
										ret[ret.length] = value;
									}
								}
							}
							return ret.concat.apply([], ret);
						},
						/**
						 * 合并数组，将second（数组或类数组）中的值合并到first中
						 * @param {Object} first
						 * @param {Object} second
						 */
						merge: function( first, second ) {  
    						//如果second.length是一个字符串，那么+second.length就是数字了，通过typeof +"123"将返回number  
    						//如果是+ "xx"那么就会返回0，typeof还是会返回number  
							var len = +second.length, j = 0,  i = first.length;  
							
							//通过i不断的往里面添加，数组长度自动增加  
							while ( j < len ) {  
							   first[ i++ ] = second[ j++ ];  
							}  
							//在IE<9中，会把NodeList等类数组对象的length转为NaN  
							if ( len !== len ) {  
								while ( second[j] !== undefined ) {  
									first[ i++ ] = second[ j++ ];  
								}  
							}  
							//重新设置数组长度，数组的长度一般是number类型  
							first.length = i;  
							return first;  
						}  
						
					});

					return jQuery;
				})();
				window.jQuery = window.$ = jQuery;
				
			})(window);

			$('');
			console.log(jQuery.isFunction(console.log));
			console.log(new String(undefined));
			console.log(jQuery.type(new Date()));
			console.log($.isWindow(window));
			console.log(typeof 1);
			console.log(' 1 '.trim());
			console.log(jQuery.isPlainObject(new Date()));
			console.log(jQuery.isPlainObject({
				'test': 'ok'
			}));

			var a = {
				"a": '1',
				"b": '2'
			};
			var b = {
				"a": '3',
				"c": "f"
			};
			var c = jQuery.extend(a, b);
			for(var name in c) {
				console.log(name + ' = ' + c[name]);
			}
			console.log($.isArray([1, , , 2]));

			$.each(b, function(name) {
				console.log(name + ' = ' + c[name]);
			});

			//map函数测试
			var mapRet = $.map([1, 5, 2], function(v, index, arg) {
				return v + index + arg;
			}, 50);
			console.log(mapRet);
			$.each(mapRet, function(v, i) {
				console.log(v + '---' + i)
			});
			
			//merge
			console.log($.merge([1,3,5],[2,4]));
			
			//$.noConflict(); 
 			//$();
 	
		</script>
	</body>

</html>